using UnityEngine;
using UnityEngine;
using System.Text;
using System.Collections;
using System.Collections.Generic;

/// <summary>
/// Utils tool help class
/// </summary>
public class Utils {
	
	/// <summary>
	/// Ray the test terrain.
	/// </summary>
	/// <returns>
	/// The test terrain.
	/// </returns>
	/// <param name='_touchPos'>
	/// _touch position.
	/// </param>
	/// <param name='_collisionPos'>
	/// collision position.
	/// </param>
	public static bool RayTestTerrain(Vector3 _touchPos,ref Vector3 _collisionPos){
		return RayTestImpl(_touchPos,ref _collisionPos,(1 << 9));
	}
	
	/// <summary>
	/// Raies the test game character
	/// </summary>
	/// <returns>
	/// The test game cha.
	/// </returns>
	/// <param name='_touchPos'>
	/// If set to <c>true</c> _touch position.
	/// </param>
	/// <param name='_collistionPos'>
	/// If set to <c>true</c> _collistion position.
	/// </param>
	public static bool RayTestGameCha(Vector3 _touchPos,ref Vector3 _collisionPos){
		return RayTestImpl(_touchPos,ref _collisionPos,(1 << 10));
	}
	
	/// <summary>
	/// return the current time stamp
	/// </summary>
	/// <returns>
	/// return the current time stamp
	/// </returns>
	public static long CurrTimeStamp(){
		// 
		//long t_delta = System.DateTime.Parse("1970-01-01 00:00:00").Ticks;
		//t_delta == 621355968000000000
		//
		return (System.DateTime.UtcNow.Ticks - 621355968000000000L) / 10000;
	}
	
	/// <summary>
	/// Times the stamp format.
	/// 1365415509 will export 2013-04-08 18:05:09
	/// </summary>
	/// <returns>
	/// The stamp format.
	/// </returns>
	/// <param name='timeStamp'>
	/// Time stamp 
	/// </param>
	public static string TimeStampFormat(int timeStamp){
		
		// The GMT TimeZone is different with Local TimeZone
		long cTicks = timeStamp * 10000000L + 621355968000000000L; // GMT + 8Time zone
		System.DateTime dtt = System.TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(cTicks));

		return dtt.ToString("yyyy-MM-dd HH:mm:ss");
	}
	
	private static bool RayTestImpl(Vector3 _touchPos,ref Vector3 _collisionPos,int layerMask){
		
		Ray ray = Camera.main.ScreenPointToRay(_touchPos);
		RaycastHit hit;
		
		bool t_hited = Physics.Raycast(ray, out hit, Mathf.Infinity,layerMask); // terrain layer is 9
		if(t_hited){
			_collisionPos = hit.point;
		}
		
		return t_hited;
	}
	
	/// <summary>
	/// Gets the call stack.
	/// </summary>
	/// <returns>
	/// The call stack.
	/// </returns>
	public static string GetCallStack(){

        StackTrace trace = new StackTrace(1, true);

        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < trace.FrameCount; i++){
            StackFrame frame = trace.GetFrame(i);
            if (i != 0){
				builder.Append("  ");
			}

            builder.Append(frame.GetMethod());

            string fileName = frame.GetFileName();

            if (!string.IsNullOrEmpty(fileName)){
				builder.Append(" (").Append(fileName)
						.Append(": ").Append(frame.GetFileLineNumber()).Append(")");
			}
            builder.AppendLine();
        }

        return builder.ToString();
    }
	
	private static Stack<char> operators = new Stack<char>();
	private static Stack<float> results = new Stack<float>();
	
	/// <summary>
	/// copy from http://www.cnblogs.com/souso/articles/1643365.html
	/// </summary>
	/// <param name="expression"></param>
	/// <returns></returns>
	private static string InfixToPostfix(string expression) {
	 
	 operators.Clear();
	 StringBuilder result = new StringBuilder();
	 for (int i = 0; i < expression.Length; i++) {
	     char ch = expression[i];
	     if (char.IsWhiteSpace(ch)) continue;
	     switch (ch) {
	         case '+': 
	         case '-':
	             while (operators.Count > 0) {
	                 char c = operators.Pop();   //pop Operator
	                 if (c == '(') {
	                     operators.Push(c);      //push Operator
	                     break;
	                 }
	                 else {
	                     result.Append(c);
	                 }
	             }
	             operators.Push(ch);
	             result.Append(" ");
	             break;
	         case '*': 
	         case '/':
	             while (operators.Count > 0) {
	                 char c = operators.Pop();
	                 if (c == '(') {
	                     operators.Push(c);
	                     break;
	                 }
	                 else {
	                     if (c == '+' || c == '-') {
	                         operators.Push(c);
	                         break;
	                     }
	                     else {
	                         result.Append(c);
	                     }
	                 }
	             }
	             operators.Push(ch);
	             result.Append(" ");
	             break;
	         case '(':
	             operators.Push(ch);
	             break;
	         case ')':
	             while (operators.Count > 0) {
	                 char c = operators.Pop();
	                 if (c == '(') {
	                     break;
	                 }
	                 else {
	                     result.Append(c);
	                 }
	             }
	             break;
	         default:
	             result.Append(ch);
	             break;
	     }
	 }
	 while (operators.Count > 0){
	     result.Append(operators.Pop()); //pop All Operator
	 }
	 return result.ToString();
	}
	
	/// <summary>
	/// Parses the arithmetic exp.copy from http://www.cnblogs.com/souso/articles/1643365.html
	/// </summary>
	/// <returns>
	/// The arithmetic exp.
	/// </returns>
	/// <param name='expression'>
	/// Expression.
	/// </param>
	public static float ParseArithmeticExp(string expression)
	{
	    string postfixExpression = InfixToPostfix(expression);
	 	results.Clear();
		
	    float x, y;
	    for (int i = 0; i < postfixExpression.Length; i++)
	    {
	        char ch = postfixExpression[i];
	        if (char.IsWhiteSpace(ch)) continue;
	        switch (ch)
	        {
	            case '+':
	                y = results.Pop();
	                x = results.Pop();
	                results.Push(x + y);
	                break;
	            case '-':
	                y = results.Pop();
	                x = results.Pop();
	                results.Push(x - y);
	                break;
	            case '*':
	                y = results.Pop();
	                x = results.Pop();
	                results.Push(x * y);
	                break;
	            case '/':
	                y = results.Pop();
	                x = results.Pop();
	                results.Push(x / y);
	                break;
	            default:
	                int pos = i;
	                StringBuilder operand = new StringBuilder();
	                do
	                {
	                    operand.Append(postfixExpression[pos]);
	                    pos++;
	                } while (char.IsDigit(postfixExpression[pos]) || postfixExpression[pos] == '.');
	                i = --pos;
	                results.Push(float.Parse(operand.ToString()));
	                break;
	        }
	    }
	    return results.Peek();
	}
}
